package v1

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
	"maya-service/bll"
	log "maya-service/collector/logger"
	"maya-service/config"
	"maya-service/model"
	"maya-service/model/po"
	"maya-service/server/web/middleware"
	"maya-service/store/mysql"
	"maya-service/store/redis"
	"maya-service/utils"
	"maya-service/utils/request"
	"time"
)

var SupervisorWithDraw = &supervisorWithDraw{}

func init() {
	RegisterRouter(SupervisorWithDraw)
}

type supervisorWithDraw struct{}

// Init
func (a *supervisorWithDraw) Init(r *gin.RouterGroup) {
	g := r.Group("/supervisorWithDraw", middleware.Auth())
	{
		g.POST("/create", a.create)
		g.POST("/update", a.update)
		g.POST("/list", a.list)
		g.POST("/delete", a.delete)
		g.POST("/detail", a.find)
		g.POST("/agree", a.agree)
		g.POST("/withDraw", a.withDraw)
	}
}

func (a *supervisorWithDraw) withDraw(c *gin.Context) {
	var (
		in  = &po.SupervisorWithDrawAgreeReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	// 校验督导师
	supervisorId := ""
	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
		supervisorId = userId
	}

	if in.SupervisorId != "" {
		supervisorId = in.SupervisorId
	}

	// 统计待提现订单数量，统计总金额
	status := 0
	list, _ := bll.SupervisorOrder.List(c.Request.Context(), &model.SupervisorOrderListRequest{
		SupervisorId: &supervisorId,
		Status:       &status,
		Index:        1,
		Size:         10000,
	})

	if len(list.List) < 0 {
		utils.ResponseOkWithError(c, "没有可结算的订单")
		return
	}

	userInfo, _ := bll.GetUserInfoById(c.Request.Context(), supervisorId)
	withDrawCreate := &model.SupervisorWithDrawCreateRequest{
		UserId:         in.UserId,
		SupervisorId:   supervisorId,
		SupervisorName: userInfo.UserName,
	}

	nowUnix := time.Now().Unix()
	withDrawData := &po.WithDrawData{}
	var ids []int64
	var consultIds []int64
	for i := 0; i < len(list.List); i++ {
		withDrawData.TotalAmount += list.List[i].Price
		withDrawData.DeductAmount += list.List[i].DeductCount
		if nowUnix-list.List[i].CreatedAt < 7*24*3600 {
			withDrawData.FrozenAmount += list.List[i].Price
			withDrawData.FrozenDeduct += list.List[i].DeductCount
		} else {
			ids = append(ids, list.List[i].Id)
			consultIds = append(consultIds, list.List[i].ConsultId)
			withDrawCreate.OrderCount++
			withDrawCreate.TotalAmount += list.List[i].Price
			withDrawCreate.DeductAmount += list.List[i].DeductCount
		}
	}

	if len(ids) <= 0 {
		utils.ResponseOkWithError(c, "没有可结算的订单")
		return
	}

	// 执行更新
	withDrawCreate.ItemList = utils.ToJsonString(ids)
	err = mysql.SupervisorOrder.ExecTransaction(c.Request.Context(), func(ctx context.Context) error {
		// 更新order订单为已处理
		_status := 1
		if err = bll.SupervisorOrder.Update(ctx, &model.SupervisorOrderUpdateRequest{
			Ids:    ids,
			Status: &_status,
		}); err != nil {
			return err
		}

		payStatus := 1
		err = bll.AiConsult.Update(ctx, &model.AiConsultUpdateRequest{
			Ids:       consultIds,
			PayStatus: &payStatus,
		})
		if err != nil {
			return err
		}

		// 创建待提现记录
		err = bll.SupervisorWithDraw.Create(ctx, withDrawCreate)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		c.Error(err)
		return
	}

	utils.ResponseOk(c, &po.WithDrawResp{
		SupervisorId: supervisorId,
		ItemList:     withDrawCreate.ItemList,
		TotalAmount:  withDrawCreate.TotalAmount,
		DeductAmount: withDrawCreate.DeductAmount,
	})
	return
}

// agree 同意
func (a *supervisorWithDraw) agree(c *gin.Context) {
	var (
		in  = &po.SupervisorWithDrawAgreeReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	// 结算
	if in.AgreeType == 0 {
		err = mysql.SupervisorWithDraw.ExecTransaction(c.Request.Context(), func(ctx context.Context) error {
			// 读取结算记录表金额
			status := 0
			find, err := bll.SupervisorWithDraw.Find(ctx, &model.SupervisorWithDrawInfoRequest{
				Id:           in.WithDrawId,
				Status:       &status,
				SupervisorId: in.SupervisorId,
			})
			if find.Id <= 0 || err != nil || find.Status > 0 {
				return fmt.Errorf("当前用户没有待结算的记录")
			}

			// 更新结算记录表状态
			status = 1
			user, _ := request.GetUserData(ctx)
			err = bll.SupervisorWithDraw.Update(ctx, &model.SupervisorWithDrawUpdateRequest{
				Id:         find.Id,
				Status:     &status,
				OperatorId: &user.Unionid,
				Operator:   &user.UserName,
			})
			if err != nil {
				return err
			}
			// 查找用户数据
			info, err := bll.UserRecord.Find(ctx, &model.UserRecordInfoRequest{
				UserId: in.SupervisorId,
			})
			if err != nil {
				return err
			}

			// 更新用户金额数额
			delta, _ := decimal.NewFromFloat32(float32(find.TotalAmount)).Sub(decimal.NewFromFloat32(float32(find.DeductAmount))).Float64()
			if delta < 0 {
				log.Info("supervisorWithDraw agree", zap.Any("SupervisorId", in.SupervisorId), zap.Any("withDrawId", in.WithDrawId), zap.Any("in", in))
				return fmt.Errorf("提现异常，差额小于0")
			}

			// 变更
			userMoney, _ := decimal.NewFromFloat32(float32(info.UserMoney)).Add(decimal.NewFromFloat32(float32(delta))).Float64()
			err = bll.UserRecord.Update(ctx, &model.UserRecordUpdateRequest{
				UserId:        &in.SupervisorId,
				UserMoney:     &userMoney,
				WithdrawMoney: nil,
			})
			return err
		})
		if err != nil {
			utils.ResponseOkWithError(c, err.Error())
			return
		}

		utils.ResponseOk(c, nil)
		return
	}

	// 申请转账
	err = mysql.SupervisorWithDrawTrans.ExecTransaction(c.Request.Context(), func(ctx context.Context) error {
		// 查找用户数据
		info, err := bll.UserRecord.Find(ctx, &model.UserRecordInfoRequest{
			UserId: in.SupervisorId,
		})
		if err != nil {
			return err
		}

		// 记录不存在
		find, err := bll.SupervisorWithDrawTrans.Find(ctx, &model.SupervisorWithDrawTransInfoRequest{Id: in.WithDrawId})
		if err != nil || find.Id <= 0 {
			return err
		}

		// 校验
		if info.UserMoney < find.Delta {
			return fmt.Errorf("超出最大提现金额")
		}

		// 执行转账
		bSuccess := true
		err = request.Charge(config.Conf.Env, "ogHOq6c6HgiEOLdtqlbr7ggavKAo", find.Id, find.Delta)
		if err != nil {
			bSuccess = false
			return err
		} else {
			log.Info("转账成功 ", zap.Any("in", utils.ToJsonString(in)))
		}

		if !bSuccess {
			leftMoney := utils.Add(info.UserMoney, find.Delta)
			err = bll.UserRecord.Update(c.Request.Context(), &model.UserRecordUpdateRequest{UserId: &in.SupervisorId, UserMoney: &leftMoney})
			if err != nil {
				log.Error("退还用金额失败", zap.Any("userId", in.SupervisorId), zap.Any("userMoney", info.UserMoney), zap.Any("delta", find.Delta))
				return fmt.Errorf("退还用金额失败")
			}
			return nil
		}

		// 用户金额
		userMoney := utils.Sub(info.UserMoney, find.Delta)
		withdrawMoney := utils.Add(info.WithdrawMoney, find.Delta)
		err = bll.UserRecord.Update(ctx, &model.UserRecordUpdateRequest{
			UserId:        &in.SupervisorId,
			UserMoney:     &userMoney,
			WithdrawMoney: &withdrawMoney,
		})

		// 更新交易记录
		status := 1 // 0 审核中 1 打款成功 2 打款失败
		totalAmount := utils.Sub(info.UserMoney, find.Delta)
		user, _ := request.GetUserData(ctx)
		return bll.SupervisorWithDrawTrans.Update(ctx, &model.SupervisorWithDrawTransUpdateRequest{
			Id:          in.WithDrawId,
			TotalAmount: &totalAmount,
			Status:      &status,
			Operator:    &user.UserName,
			OperatorId:  &user.Unionid,
		})
	})
	if err != nil {
		c.Error(err)
		return
	}

	utils.ResponseOk(c, nil)
}

// create
func (a *supervisorWithDraw) create(c *gin.Context) {
	var (
		in  = &model.SupervisorWithDrawCreateRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.UserId == "" {
		userId, err := request.GetUserId(c.Request.Context())
		if err != nil {
			c.Error(err)
			return
		}
		in.UserId = userId
	}

	in.SupervisorId = in.UserId

	// 加分布式锁
	key := fmt.Sprintf("withDraw:%v", in.SupervisorId)
	bSuccess, err := redis.KV.SetNX(c.Request.Context(), key, 1, time.Second*120).Result()
	defer redis.KV.Del(c.Request.Context(), key)
	if err != nil || !bSuccess {
		utils.ResponseOk(c, nil)
		return
	}

	// 督导师判断
	find, _ := bll.UserRecord.Find(c.Request.Context(), &model.UserRecordInfoRequest{
		UserId: in.UserId,
	})
	if find.Id <= 0 || (find.Supervisor <= 0) {
		utils.ResponseOkWithError(c, "不是督导师，不能提交审核")
		return
	}

	// 查找督导师订单表
	in.Status = 0
	orderList, _ := bll.SupervisorOrder.List(c.Request.Context(), &model.SupervisorOrderListRequest{
		SupervisorId: &in.UserId,
		Status:       &in.Status,
		Index:        1,
		Size:         10000,
	})

	if len(orderList.List) <= 0 {
		utils.ResponseOkWithError(c, "没有可以提现的订单")
		return
	}

	in = &model.SupervisorWithDrawCreateRequest{
		SupervisorId: in.UserId,
		OrderCount:   len(orderList.List),
	}

	// 导师名字
	info, _ := bll.GetUserInfoById(c.Request.Context(), in.UserId)
	if info != nil {
		in.SupervisorName = info.UserName
	}

	// 订单ID列表
	var orderIds []int64
	for i := 0; i < len(orderList.List); i++ {
		orderIds = append(orderIds, orderList.List[i].Id)
		in.TotalAmount += orderList.List[i].Price
		in.DeductAmount += orderList.List[i].DeductCount
	}

	in.ItemList = utils.ToJsonString(orderIds)

	// 执行更新
	err = mysql.SupervisorOrder.ExecTransaction(c.Request.Context(), func(ctx context.Context) error {
		// 更新order订单为已处理
		status := 1
		if err = bll.SupervisorOrder.Update(ctx, &model.SupervisorOrderUpdateRequest{
			Ids:    orderIds,
			Status: &status,
		}); err != nil {
			return err
		}
		// 创建待提现记录
		if err = bll.SupervisorWithDraw.Create(ctx, in); err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		c.Error(err)
		return
	}

	utils.ResponseOk(c, nil)
}

// update
func (a *supervisorWithDraw) update(c *gin.Context) {
	var (
		in  = &model.SupervisorWithDrawUpdateRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if err = bll.SupervisorWithDraw.Update(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, nil)
}

// list
func (a *supervisorWithDraw) list(c *gin.Context) {
	var (
		in  = &model.SupervisorWithDrawListRequest{}
		out = &model.SupervisorWithDrawListResponse{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if out, err = bll.SupervisorWithDraw.List(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}

	utils.ResponseOk(c, out)
}

// list
func (a *supervisorWithDraw) find(c *gin.Context) {
	var (
		in  = &model.SupervisorWithDrawInfoRequest{}
		out = &model.SupervisorWithDrawInfo{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if out, err = bll.SupervisorWithDraw.Find(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, out)
}

// delete
func (a *supervisorWithDraw) delete(c *gin.Context) {
	var (
		in  = &model.SupervisorWithDrawDeleteRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if err = bll.SupervisorWithDraw.Delete(c.Request.Context(), in); err != nil {
		c.Error(err)
		return
	}
	utils.ResponseOk(c, nil)
}
